
/*
 * Copyright 2002-2020 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
/*
 *版权所有2002-2020原作者。
 *
 *根据Apache许可证2.0版（“许可证”）获得许可；
 *除非符合许可证，否则不得使用此文件。
 *您可以在以下地址获取许可证副本：
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 *除非适用法律要求或书面同意，软件
 *根据许可证分发的内容是按“原样”分发的，
 *无任何明示或暗示的保证或条件。
 *有关管理权限和
 *许可证下的限制。
 */

package org.springframework.aop.interceptor;

import java.io.Serializable;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import org.springframework.aop.support.AopUtils;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;

/**
 * Base {@code MethodInterceptor} implementation for tracing.
 *
 * <p>By default, log messages are written to the log for the interceptor class,
 * not the class which is being intercepted. Setting the {@code useDynamicLogger}
 * bean property to {@code true} causes all log messages to be written to
 * the {@code Log} for the target class being intercepted.
 *
 * <p>Subclasses must implement the {@code invokeUnderTrace} method, which
 * is invoked by this class ONLY when a particular invocation SHOULD be traced.
 * Subclasses should write to the {@code Log} instance provided.
 *
 * @author Rob Harrop
 * @author Juergen Hoeller
 * @since 1.2
 * @see #setUseDynamicLogger
 * @see #invokeUnderTrace(org.aopalliance.intercept.MethodInvocation, org.apache.commons.logging.Log)
 */
/**
 *用于跟踪的基｛@code MethodInterceptor｝实现。
 *
 *＜p＞默认情况下，日志消息被写入拦截器类的日志，
 *而不是被拦截的类。正在设置｛@code useDynamicLogger｝
 *｛@code true｝的bean属性将导致所有日志消息都写入
 *正在拦截的目标类的｛@code Log｝。
 *
 *＜p＞子类必须实现｛@code invokeUnderTrace｝方法，该方法
 *仅当应跟踪特定调用时，才由此类调用。
 *子类应写入提供的｛@code Log｝实例。
 *
 *@作者Rob Harrop
 *@作者Juergen Hoeller
 *@自1.2
 *@参见#setUseDynamicLogger
 *@参见#invokeUnderTrace（org.opalliance.intercept.MethodInvocation，org.apache.commons.loging.Log）
 */
@SuppressWarnings("serial")
public abstract class AbstractTraceInterceptor implements MethodInterceptor, Serializable {

	/**
	 * The default {@code Log} instance used to write trace messages.
	 * This instance is mapped to the implementing {@code Class}.
	 */
	/**
	 *用于写入跟踪消息的默认｛@code Log｝实例。
	 *此实例映射到实现的｛@code Class｝。
	 */
	@Nullable
	protected transient Log defaultLogger = LogFactory.getLog(getClass());

	/**
	 * Indicates whether proxy class names should be hidden when using dynamic loggers.
	 * @see #setUseDynamicLogger
	 */
	/**
	 *指示在使用动态记录器时是否应隐藏代理类名。
	 *@参见#setUseDynamicLogger
	 */
	private boolean hideProxyClassNames = false;

	/**
	 * Indicates whether to pass an exception to the logger.
	 * @see #writeToLog(Log, String, Throwable)
	 */
	/**
	 *指示是否向记录器传递异常。
	 *@see#writeToLog（Log，String，Throwable）
	 */
	private boolean logExceptionStackTrace = true;


	/**
	 * Set whether to use a dynamic logger or a static logger.
	 * Default is a static logger for this trace interceptor.
	 * <p>Used to determine which {@code Log} instance should be used to write
	 * log messages for a particular method invocation: a dynamic one for the
	 * {@code Class} getting called, or a static one for the {@code Class}
	 * of the trace interceptor.
	 * <p><b>NOTE:</b> Specify either this property or "loggerName", not both.
	 * @see #getLoggerForInvocation(org.aopalliance.intercept.MethodInvocation)
	 */
	/**
	 *设置是使用动态记录器还是静态记录器。
	 *默认值是此跟踪拦截器的静态记录器。
	 *＜p＞用于确定应该使用哪个｛@code Log｝实例来编写
	 *特定方法调用的日志消息：
	 *｛@code Class｝被调用，或｛@codeClass｝的静态调用
	 *跟踪拦截器的。
	 *<p><b>注意：</b>指定此属性或“loggerName”，而不是同时指定两者。
	 *@参见#getLoggerForInvocation（org.aopalliance.incept.MethodInvocation）
	 */
	public void setUseDynamicLogger(boolean useDynamicLogger) {
		// Release default logger if it is not being used.
		// 如果未使用默认记录器，请释放它。
		this.defaultLogger = (useDynamicLogger ? null : LogFactory.getLog(getClass()));
	}

	/**
	 * Set the name of the logger to use. The name will be passed to the
	 * underlying logger implementation through Commons Logging, getting
	 * interpreted as log category according to the logger's configuration.
	 * <p>This can be specified to not log into the category of a class
	 * (whether this interceptor's class or the class getting called)
	 * but rather into a specific named category.
	 * <p><b>NOTE:</b> Specify either this property or "useDynamicLogger", not both.
	 * @see org.apache.commons.logging.LogFactory#getLog(String)
	 * @see java.util.logging.Logger#getLogger(String)
	 */
	/**
	 *设置要使用的记录器的名称。名称将传递给
	 *通过CommonsLogging实现底层记录器
	 *根据记录器的配置解释为日志类别。
	 *＜p＞这可以指定为不登录到类的类别
	 *（无论是该拦截器的类还是被调用的类）
	 *而是分成特定的命名类别。
	 *<p><b>注意：</b>指定此属性或“useDynamicLogger”，而不是同时指定两者。
	 *@see org.apache.commons.loging.LogFactory#getLog（字符串）
	 *@see java.util.loging.Logger#getLogger（字符串）
	 */
	public void setLoggerName(String loggerName) {
		this.defaultLogger = LogFactory.getLog(loggerName);
	}

	/**
	 * Set to "true" to have {@link #setUseDynamicLogger dynamic loggers} hide
	 * proxy class names wherever possible. Default is "false".
	 */
	/**
	 *设置为“true”以隐藏｛@link#setUseDynamicLogger动态记录器｝
	 *尽可能使用代理类名。默认值为“false”。
	 */
	public void setHideProxyClassNames(boolean hideProxyClassNames) {
		this.hideProxyClassNames = hideProxyClassNames;
	}

	/**
	 * Set whether to pass an exception to the logger, suggesting inclusion
	 * of its stack trace into the log. Default is "true"; set this to "false"
	 * in order to reduce the log output to just the trace message (which may
	 * include the exception class name and exception message, if applicable).
	 * @since 4.3.10
	 */
	/**
	 *设置是否向记录器传递异常，建议包含
	 *将其堆栈跟踪记录到日志中。默认值为“true”；将此设置为“false”
	 *以便将日志输出减少为仅跟踪消息（可能
	 *包括异常类名和异常消息（如果适用）。
	 *@自4.3.10
	 */
	public void setLogExceptionStackTrace(boolean logExceptionStackTrace) {
		this.logExceptionStackTrace = logExceptionStackTrace;
	}


	/**
	 * Determines whether logging is enabled for the particular {@code MethodInvocation}.
	 * If not, the method invocation proceeds as normal, otherwise the method invocation is passed
	 * to the {@code invokeUnderTrace} method for handling.
	 * @see #invokeUnderTrace(org.aopalliance.intercept.MethodInvocation, org.apache.commons.logging.Log)
	 */
	/**
	 *确定是否为特定｛@code MethodInvocation｝启用日志记录。
	 *如果没有，方法调用将照常进行，否则将传递方法调用
	 *到｛@code invokeUnderTrace｝方法进行处理。
	 *@参见#invokeUnderTrace（org.opalliance.intercept.MethodInvocation，org.apache.commons.loging.Log）
	 */
	@Override
	@Nullable
	public Object invoke(MethodInvocation invocation) throws Throwable {
		Log logger = getLoggerForInvocation(invocation);
		if (isInterceptorEnabled(invocation, logger)) {
			return invokeUnderTrace(invocation, logger);
		}
		else {
			return invocation.proceed();
		}
	}

	/**
	 * Return the appropriate {@code Log} instance to use for the given
	 * {@code MethodInvocation}. If the {@code useDynamicLogger} flag
	 * is set, the {@code Log} instance will be for the target class of the
	 * {@code MethodInvocation}, otherwise the {@code Log} will be the
	 * default static logger.
	 * @param invocation the {@code MethodInvocation} being traced
	 * @return the {@code Log} instance to use
	 * @see #setUseDynamicLogger
	 */
	/**
	 *返回相应的｛@code Log｝实例以用于给定的
	 *｛@code MethodInvocation｝。如果｛@code useDynamicLogger｝标志
	 *｛@code Log｝实例将用于
	 *｛@code MethodInvocation｝，否则｛@codeLog｝将是
	 *默认静态记录器。
	 *@param调用正在跟踪的｛@code MethodInvocation｝
	 *@return要使用的｛@code Log｝实例
	 *@参见#setUseDynamicLogger
	 */
	protected Log getLoggerForInvocation(MethodInvocation invocation) {
		if (this.defaultLogger != null) {
			return this.defaultLogger;
		}
		else {
			Object target = invocation.getThis();
			Assert.state(target != null, "Target must not be null");
			return LogFactory.getLog(getClassForLogging(target));
		}
	}

	/**
	 * Determine the class to use for logging purposes.
	 * @param target the target object to introspect
	 * @return the target class for the given object
	 * @see #setHideProxyClassNames
	 */
	/**
	 *确定用于日志记录的类。
	 *@param target要内省的目标对象
	 *@返回给定对象的目标类
	 *@参见#setHideProxyClassNames
	 */
	protected Class<?> getClassForLogging(Object target) {
		return (this.hideProxyClassNames ? AopUtils.getTargetClass(target) : target.getClass());
	}

	/**
	 * Determine whether the interceptor should kick in, that is,
	 * whether the {@code invokeUnderTrace} method should be called.
	 * <p>Default behavior is to check whether the given {@code Log}
	 * instance is enabled. Subclasses can override this to apply the
	 * interceptor in other cases as well.
	 * @param invocation the {@code MethodInvocation} being traced
	 * @param logger the {@code Log} instance to check
	 * @see #invokeUnderTrace
	 * @see #isLogEnabled
	 */
	/**
	 *确定拦截器是否应该启动，
	 *是否应调用｛@code invokeUnderTrace｝方法。
	 *＜p＞默认行为是检查给定的｛@code Log｝
	 *实例已启用。子类可以重写此以应用
	 *在其他情况下，拦截器也是如此。
	 *@param调用正在跟踪的｛@code MethodInvocation｝
	 *@param记录要检查的｛@code Log｝实例
	 *@参见#invokeUnderTrace
	 *@参见#isLogEnabled
	 */
	protected boolean isInterceptorEnabled(MethodInvocation invocation, Log logger) {
		return isLogEnabled(logger);
	}

	/**
	 * Determine whether the given {@link Log} instance is enabled.
	 * <p>Default is {@code true} when the "trace" level is enabled.
	 * Subclasses can override this to change the level under which 'tracing' occurs.
	 * @param logger the {@code Log} instance to check
	 */
	/**
	 *确定给定的｛@link Log｝实例是否已启用。
	 *＜p＞启用“跟踪”级别时，默认值为｛@code true｝。
	 *子类可以覆盖此项以更改发生“跟踪”的级别。
	 *@param记录要检查的｛@code Log｝实例
	 */
	protected boolean isLogEnabled(Log logger) {
		return logger.isTraceEnabled();
	}

	/**
	 * Write the supplied trace message to the supplied {@code Log} instance.
	 * <p>To be called by {@link #invokeUnderTrace} for enter/exit messages.
	 * <p>Delegates to {@link #writeToLog(Log, String, Throwable)} as the
	 * ultimate delegate that controls the underlying logger invocation.
	 * @since 4.3.10
	 * @see #writeToLog(Log, String, Throwable)
	 */
	/**
	 *将提供的跟踪消息写入提供的｛@code Log｝实例。
	 *＜p＞由｛@link#invokeUnderTrace｝调用以获取进入/退出消息。
	 *＜p＞委托｛@link#writeToLog（Log，String，Throwable）｝作为
	 *控制底层记录器调用的最终委托。
	 *@自4.3.10
	 *@see#writeToLog（Log，String，Throwable）
	 */
	protected void writeToLog(Log logger, String message) {
		writeToLog(logger, message, null);
	}

	/**
	 * Write the supplied trace message and {@link Throwable} to the
	 * supplied {@code Log} instance.
	 * <p>To be called by {@link #invokeUnderTrace} for enter/exit outcomes,
	 * potentially including an exception. Note that an exception's stack trace
	 * won't get logged when {@link #setLogExceptionStackTrace} is "false".
	 * <p>By default messages are written at {@code TRACE} level. Subclasses
	 * can override this method to control which level the message is written
	 * at, typically also overriding {@link #isLogEnabled} accordingly.
	 * @since 4.3.10
	 * @see #setLogExceptionStackTrace
	 * @see #isLogEnabled
	 */
	/**
	 *将提供的跟踪消息和｛@link Throwable｝写入
	 *提供了｛@code Log｝实例。
	 *＜p＞由｛@link#invokeUnderTrace｝调用以获得进入/退出结果，
	 *可能包括异常。注意，异常的堆栈跟踪
	 *当｛@link#setLogExceptionStackTrace｝为“false”时，不会被记录。
	 *＜p＞默认情况下，消息是在｛@code TRACE｝级别编写的。子类
	 *可以重写此方法以控制写入消息的级别
	 *at，通常也会相应地重写｛@link#isLogEnabled｝。
	 *@自4.3.10
	 *@参见#setLogExceptionStackTrace
	 *@参见#isLogEnabled
	 */
	protected void writeToLog(Log logger, String message, @Nullable Throwable ex) {
		if (ex != null && this.logExceptionStackTrace) {
			logger.trace(message, ex);
		}
		else {
			logger.trace(message);
		}
	}


	/**
	 * Subclasses must override this method to perform any tracing around the
	 * supplied {@code MethodInvocation}. Subclasses are responsible for
	 * ensuring that the {@code MethodInvocation} actually executes by
	 * calling {@code MethodInvocation.proceed()}.
	 * <p>By default, the passed-in {@code Log} instance will have log level
	 * "trace" enabled. Subclasses do not have to check for this again, unless
	 * they overwrite the {@code isInterceptorEnabled} method to modify
	 * the default behavior, and may delegate to {@code writeToLog} for actual
	 * messages to be written.
	 * @param logger the {@code Log} to write trace messages to
	 * @return the result of the call to {@code MethodInvocation.proceed()}
	 * @throws Throwable if the call to {@code MethodInvocation.proceed()}
	 * encountered any errors
	 * @see #isLogEnabled
	 * @see #writeToLog(Log, String)
	 * @see #writeToLog(Log, String, Throwable)
	 */
	/**
	 *子类必须重写此方法，以对
	 *提供了｛@code MethodInvocation｝。子类负责
	 *确保｛@code MethodInvocation｝实际上由
	 *调用｛@code MethodInvocation.proceed（）｝。
	 *＜p＞默认情况下，传入的｛@code Log｝实例将具有日志级别
	 *“跟踪”已启用。子类不必再次检查，除非
	 *它们覆盖｛@code isInterceptorEnabled｝方法以修改
	 *默认行为，并且可以委托给｛@code writeToLog｝以获取实际
	 *要写入的消息。
	 *@param记录要向其写入跟踪消息的｛@code Log｝
	 *@返回调用｛@code MethodInvocation.proceed（）｝的结果
	 *@throws如果调用｛@code MethodInvocation.proceed（）｝
	 *遇到任何错误
	 *@参见#isLogEnabled
	 *@see#writeToLog（日志，字符串）
	 *@see#writeToLog（Log，String，Throwable）
	 */
	@Nullable
	protected abstract Object invokeUnderTrace(MethodInvocation invocation, Log logger) throws Throwable;

}
